package com.star.uc.infras.filter;

import com.alibaba.fastjson2.JSON;
import com.google.common.base.Stopwatch;
import com.star.common.core.contract.R;
import com.star.common.core.contract.enums.ResultCodeEnum;
import com.star.common.kit.ip.IpUtil;
import com.star.common.protocol.contract.dto.HeaderDTO;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.web.util.ContentCachingResponseWrapper;

import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

/**
 * 请求响应日志
 *
 * @author zhouhengzhe
 */
@Slf4j
public class RequestResponseLogFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        String url = httpServletRequest.getRequestURL().toString();
        RepeatReadRequestWrapper repeatReadRequestWrapper = new RepeatReadRequestWrapper(httpServletRequest);
        ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper((HttpServletResponse) servletResponse);
        String body = IOUtils.toString(repeatReadRequestWrapper.getInputStream(), StandardCharsets.UTF_8);
        String ip = IpUtil.toIpAddr(httpServletRequest);
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            HeaderDTO headerDTO = HeaderDTO.parseForRequestHeader(httpServletRequest);
            //设置请求头
            HeaderDTO.setHeaderContext(headerDTO);
            filterChain.doFilter(repeatReadRequestWrapper, responseWrapper);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            responseWrapper.setCharacterEncoding("UTF-8");
            responseWrapper.setContentType("application/json; charset=utf-8");
            PrintWriter out = responseWrapper.getWriter();
            //todo 多语言的话，此处需要改造
            R r = new R(ResultCodeEnum.FAIL.getCode(), ResultCodeEnum.FAIL.getDesc());
            out.append(JSON.toJSONString(r));
            out.flush();
        } finally {
            long runtime = stopwatch.elapsed(TimeUnit.MILLISECONDS);
            String responseBody = getResponseBody(responseWrapper);
            log.info("Request URL: {},Remote IP:{},Request Header:{}, Request Body: {}," +
                            " Duration: {} ms, Response Status: {},Response Body: {} ",
                    url, ip, JSON.toJSONString(HeaderDTO.getHeaderContext()), body,
                    runtime, responseWrapper.getStatus(), responseBody);
            HeaderDTO.clearHeaderContext();
        }
    }

    private String getResponseBody(ContentCachingResponseWrapper responseWrapper) throws IOException {
        byte[] responseBody = responseWrapper.getContentAsByteArray();
        responseWrapper.copyBodyToResponse();
        return new String(responseBody, StandardCharsets.UTF_8);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}
